﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;
using Microsoft.Kinect;
using Coding4Fun.Kinect.Wpf;

namespace EarthDemo
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑 17Ch
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            // CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering); // 加入自动旋转
        }

        const int skeletonCount = 6;
        Skeleton[] allSkeletons = new Skeleton[skeletonCount];
        const float MaxDepthDistance = 4095; // max value returned
        const float MinDepthDistance = 850; // min value returned
        const float MaxDepthDistanceOffset = MaxDepthDistance - MinDepthDistance;
        KinectSensor _sensor;

        private void main_window_Loaded(object sender, RoutedEventArgs e)
        {
            if (KinectSensor.KinectSensors.Count > 0)
            {
                _sensor = KinectSensor.KinectSensors[0];
                if (_sensor.Status == KinectStatus.Connected)
                {

                    var parameters = new TransformSmoothParameters
                    {
                        Smoothing = 0.3f,
                        Correction = 0.0f,
                        Prediction = 0.0f,
                        JitterRadius = 1.0f,
                        MaxDeviationRadius = 0.5f
                    };
                    //_sensor.SkeletonStream.Enable(parameters);
                    _sensor.SkeletonStream.Enable();
                    _sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
                    _sensor.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30);

                    _sensor.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(_sensor_ColorFrameReady);
                    _sensor.DepthFrameReady += new EventHandler<DepthImageFrameReadyEventArgs>(_sensor_DepthFrameReady);
                    //_sensor.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(_sensor_SkeletonFrameReady);
                    _sensor.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(_sensor_AllFramesReady);
                    _sensor.Start();
                    _sensor.ElevationAngle = 8;
                }
            }
        }


        void _sensor_AllFramesReady(object sender, AllFramesReadyEventArgs e)
        {
            using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
            {
                if (skeletonFrame == null)
                {
                    return;
                }
                skeletonFrame.CopySkeletonDataTo(allSkeletons);
                Skeleton first = (from s in allSkeletons
                                  where s.TrackingState == SkeletonTrackingState.Tracked
                                  select s).FirstOrDefault();
                if (first == null)
                {
                    return;
                }
                GetCameraPoint(first, e);
            }
        }

        private void GetCameraPoint(Skeleton first, AllFramesReadyEventArgs e)
        {
            using (DepthImageFrame depth = e.OpenDepthImageFrame())
            {
                if (depth == null || _sensor == null)
                {
                    return;
                }

                //                 DepthImagePoint headDepthPoint =
                //                     depth.MapFromSkeletonPoint(first.Joints[JointType.Head].Position);

                // left hand
                DepthImagePoint leftDepthPoint =
                    depth.MapFromSkeletonPoint(first.Joints[JointType.HandLeft].Position);

                // right hand
                DepthImagePoint rightDepthPoint =
                    depth.MapFromSkeletonPoint(first.Joints[JointType.HandRight].Position);

                //ColorImagePoint headColorPoint =
                //    depth.MapToColorImagePoint(headDepthPoint.X, headDepthPoint.Y,
                //    ColorImageFormat.RgbResolution640x480Fps30);
                // left hand
                ColorImagePoint leftColorPoint =
                    depth.MapToColorImagePoint(leftDepthPoint.X, leftDepthPoint.Y,
                    ColorImageFormat.RgbResolution640x480Fps30);
                // right hand
                ColorImagePoint rightColorPoint =
                    depth.MapToColorImagePoint(rightDepthPoint.X, rightDepthPoint.Y,
                    ColorImageFormat.RgbResolution640x480Fps30);

                // set location
                // CameraPosition(headImage, headColorPoint);
                //CameraPosition(leftHandTag, leftColorPoint);
                //CameraPosition(rightHandTag, rightColorPoint);

                // ScalePosition(head, first.Joints[JointType.Head]);
                ScalePosition(leftHandTag, first.Joints[JointType.HandLeft]);
                ScalePosition(rightHandTag, first.Joints[JointType.HandRight]);

                // 转化坐标
                Point ptLeft = new Point(0, 0);
                Point ptRight = new Point(0, 0);
                ptLeft.X = Canvas.GetLeft(leftHandTag) + leftHandTag.Width / 2;
                ptLeft.Y = Canvas.GetTop(leftHandTag) + leftHandTag.Height / 2;
                ptRight.X = Canvas.GetLeft(rightHandTag) + rightHandTag.Width / 2;
                ptRight.Y = Canvas.GetTop(rightHandTag) + rightHandTag.Height / 2;
                Joint stand = first.Joints[JointType.Spine];               
                double relRightHandX = first.Joints[JointType.HandRight].Position.X - stand.Position.X;
                double relRightHandY = first.Joints[JointType.HandRight].Position.Y - stand.Position.Y;
                double relRightHandZ = first.Joints[JointType.HandRight].Position.Z - stand.Position.Z;
                double relLeftHandX = first.Joints[JointType.HandLeft].Position.X - stand.Position.X;
                double relLeftHandY = first.Joints[JointType.HandLeft].Position.Y - stand.Position.Y;
                double relLeftHandZ = first.Joints[JointType.HandLeft].Position.Z - stand.Position.Z;
                textBox1.Text = relLeftHandX.ToString();
                textBox2.Text = relLeftHandY.ToString();
                textBox3.Text = relRightHandZ.ToString();
                if (relLeftHandX >= -0.5 && relLeftHandX <= 0 && relLeftHandY >= 0.1 && relLeftHandY <= 0.6)
                {
                    if (isHandIn == true)
                    {
                        Draging(relRightHandX - Center, relRightHandY - Center);
                    }
                    if (relRightHandY >= High)
                    {
                        isHandIn = true;
                    }
                }
                else if (relRightHandY >= High) // 当右手高于一定值时就有效
                {
                    isHandIn = false;
                    Zooming(relRightHandZ);
                }
            }
        }
        Point ptHandIn = new Point(0, 0);
        Point ptPicIn = new Point(0, 0);
        const double DIFF = 0.45;
        bool isHandIn = false;
        const double Offset = 0.15; // 偏移校正量
        const double Center = 0.2; // 相对中心
        const double High = 0.1; // 超过一定高度有效
        private void Draging(double x, double y)
        {
            if (Math.Abs(x) > Offset)
            {
                YRotate.Angle = YRotate.Angle + x * 10;
                if (YRotate.Angle > 360)
                {
                    YRotate.Angle = YRotate.Angle - 360;
                }
                else if (YRotate.Angle < 0)
                {
                    YRotate.Angle = 360 + YRotate.Angle;
                }
            }
            if (Math.Abs(y) > Offset)
            {
                XRotate.Angle = XRotate.Angle + (-y) * 10;
                if (XRotate.Angle > 360)
                {
                    XRotate.Angle = XRotate.Angle - 360;
                }
                else if (XRotate.Angle < 0)
                {
                    XRotate.Angle = 360 + XRotate.Angle;
                }
            }
//             if (Math.Sqrt(x*x + y*y) > Offset) // 当在某个圆范围外后
//             {
//                 
//                 
//             }
        }

        private const double ZDistance = 0.5;
        private void Zooming(double dis/*Point ptLeft, Point ptRight*/)
        {
            double z = cam.Position.Z;
            if (dis < -0.45) // 前伸缩小
            {
                 z += ZDistance;
            }
            else if (dis > -0.2) // 回拉放大
            {
                z -= ZDistance;
            }
           // z += dis; //Math.Sqrt((ptLeft.X - ptRight.X) * (ptLeft.X - ptRight.X) + (ptLeft.Y - ptRight.Y) * (ptLeft.Y - ptRight.Y)); // Z轴距离减小，放大
            if (z < 5)
            {
                z = 5; // 距离拉近放大
            }
            else if(z > 40)
            {
                z = 40;
            }
            cam.Position = new Point3D(0, 0, z);
         
        }

        private void ScalePosition(FrameworkElement element, Joint joint)
        {
            //convert & scale (.3 = means 1/3 of joint distance)
            //Joint scaledJoint = joint.ScaleTo(3600, 2800, .4f, .4f);
            Joint scaledJoint = joint.ScaleTo(1920, 1080, .3f, .3f);
            Canvas.SetLeft(element, scaledJoint.Position.X);
            Canvas.SetTop(element, scaledJoint.Position.Y);
        }

        private void CameraPosition(FrameworkElement element, ColorImagePoint point)
        {
            Canvas.SetLeft(element, point.X - element.Width / 2);
            Canvas.SetTop(element, point.Y - element.Height / 2);
        }


        void _sensor_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            //throw new NotImplementedException();
            //using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
            //{
            //    if (depthFrame == null)
            //    {
            //        return;
            //    }
            //    byte[] pixels = GenerateColoredBytes(depthFrame);
            //    int stride = depthFrame.Width * 4;
            //    img_depth.Source = BitmapSource.Create(depthFrame.Width, depthFrame.Height,
            //        96, 96, PixelFormats.Bgr32, null, pixels, stride);
            //}
        }

        void _sensor_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
                if (colorFrame == null)
                {
                    return;
                }
                byte[] pixels = new byte[colorFrame.PixelDataLength];
                colorFrame.CopyPixelDataTo(pixels);
                int stride = colorFrame.Width * 4;
                img_color.Source = BitmapSource.Create(colorFrame.Width, colorFrame.Height,
                    96, 96, PixelFormats.Bgr32, null, pixels, stride);
            }
        }

        void StopKinect(KinectSensor sensor)
        {
            if (sensor != null)
            {
                sensor.Stop();
                if (sensor.AudioSource != null)
                {
                    sensor.AudioSource.Stop();
                }
            }
        }


        private byte[] GenerateColoredBytes(DepthImageFrame depthFrame)
        {
            short[] rawDepthData = new short[depthFrame.PixelDataLength];
            depthFrame.CopyPixelDataTo(rawDepthData);
            byte[] pixels = new byte[depthFrame.Width * depthFrame.Height * 4];
            const int BlueIndex = 0;
            const int GreenIndex = 1;
            const int RedIndex = 2;
            for (int depthIndex = 0, colorIndex = 0;
                depthIndex < rawDepthData.Length && colorIndex < pixels.Length;
                ++depthIndex, colorIndex += 4)
            {
                int player = rawDepthData[depthIndex] & DepthImageFrame.PlayerIndexBitmask;
                int depth = rawDepthData[depthIndex] >> DepthImageFrame.PlayerIndexBitmaskWidth;
                if (depth <= 900)
                {
                    pixels[colorIndex + BlueIndex] = 255;
                    pixels[colorIndex + GreenIndex] = 0;
                    pixels[colorIndex + RedIndex] = 0;
                }
                else if (depth > 900 && depth < 2000)
                {
                    pixels[colorIndex + BlueIndex] = 0;
                    pixels[colorIndex + GreenIndex] = 255;
                    pixels[colorIndex + RedIndex] = 0;
                }
                else if (depth > 2000)
                {
                    pixels[colorIndex + BlueIndex] = 0;
                    pixels[colorIndex + GreenIndex] = 0;
                    pixels[colorIndex + RedIndex] = 255;
                }
                byte intensity = CalculateIntensityFromeDepth(depth);
                pixels[colorIndex + BlueIndex] = intensity;
                pixels[colorIndex + GreenIndex] = intensity;
                pixels[colorIndex + RedIndex] = intensity;

                if (player > 0)
                {
                    pixels[colorIndex + BlueIndex] = Colors.Gold.B;
                    pixels[colorIndex + GreenIndex] = Colors.Gold.G;
                    pixels[colorIndex + RedIndex] = Colors.Gold.R;
                }
            }
            return pixels;
        }

        public static byte CalculateIntensityFromeDepth(int distance)
        {
            return (byte)(255 - (255 * Math.Max(distance - MinDepthDistance, 0) / (MaxDepthDistanceOffset)));
        }


        private bool isStop = false;
        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            YRotate.Angle++;
            if (YRotate.Angle > 360)
            {
                YRotate.Angle = 0;
            }
        }

        private void main_window_KeyUp(object sender, KeyEventArgs e)
        {
            switch(e.Key)
            {
                case Key.Escape:
                    Application.Current.Shutdown();
                    break;
                case Key.P:
                    if (isStop == true)
                    {
                        isStop = false;
                        CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
                    }
                    else
                    {
                        isStop = true;
                        CompositionTarget.Rendering -= new EventHandler(CompositionTarget_Rendering);
                    }
                    break;
                default:
                    break;
            }
        }

        private void main_window_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            double z = cam.Position.Z;
            //if (e.Delta > 1) // 滚轮加
            //{
            //    if (z < 4)
            //    {
            //        return;
            //    }
            //    z -= ZDistance; // Z轴距离减小，放大
            //    cam.Position = new Point3D(0, 0, z);
            //}
            //else if (z > 50) // 滚轮减
            //{
            //    return;
            //}
            //else
            //{
            //    z += ZDistance;
            //    cam.Position = new Point3D(0, 0, z);
            //}

            if (z < 4 && e.Delta > 1)
            {
                return;
            }
            else if (z > 50 && e.Delta < 1)
            {
                return;
            }
            z = z - (double)(e.Delta / 60);
            cam.Position = new Point3D(0, 0, z);
        }

        private void story_Completed(object sender, EventArgs e)
        {
            cam.Position = new Point3D(0, 0, 10);
        }

        private void main_window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            StopKinect(_sensor);
        }

        
    }
}
